/* *
*-  poolLimit :并发处理的最大数量 也就是他说的N个。
*-  array : 要处理的数据数组。
*-  iteratorFn : 处理数据的异步函数。
*-  return : 函数返回一个Promise，当所有数据都被处理完成时，该Promise会被解析为一个结果数组。
*   https://github.com/rxaviers/async-pool/blob/1.x/lib/es7.js  更标准写法
* */
//? for of async await方式  并发的做法是这样 但是要构造成class这样 离谱
async function asyncP(poolLimit,array,iteratorFn) {
    let ret = [] //? 所有任务的队列
    let poolList = [] //? 异步任务队列
    for (let i of array) {
        //? 执行异步函数处理数据 且保证结果是promise 因为需要放进promise数组。
        let p = Promise.resolve(iteratorFn(i))
        //? 放入所有任务队列
        ret.push(p)
        //? _p为p执行完成后 执行删除的回调函数
        let _p = p.then(() => {poolList.splice(poolList.indexOf(_p),1)})
        poolList.push(_p)
        if (poolList.length >= poolLimit) {
            //? 等待池子里的第一个完成腾出位置
            await Promise.race(poolList)
        }
    }
    //? Promise.all(ret) 即需要等待ret数组中的promise全部执行完成
    return Promise.all(ret)

}
asyncP(10,new Array(1000).fill(1),(num) => num + 1).then(res => console.log(res))

//? 递归方式
function asyncPool2(limit,dates,fn) {
    //? 表示已经处理的数据数量
    let count = 0;
    //? exec 数组保存当前正在并发执行的异步操作
    const exec = [];
    //? values 数组则保存所有异步操作的结果
    const values = [];
    //? 一个内部函数 _asyncPool ，它是一个递归函数，会迭代地处理每一个数据。如果所有数据都已经处理完毕，函数会返回一个已解决的Promise
    const _asyncPool = () => {
        //? 递归结束条件
        if (count === dates.length) {
            return Promise.resolve();
        }
        //? 取出待处理数据
        const item = dates[count++];
        //? 相当于立即执行then里的回调函数 执行处理数据的异步函数
        const p = Promise.resolve().then(() => fn(item));
        //? 保存结果(因为是异步任务所以必然此时未执行完)
        values.push(p);
        //? 该对象会等到 p 执行完成后将其从 exec 数组中删除。然后，我们将 _p 添加到 exec 数组中，以便我们可以追踪当前正在并发执行的操作
        const _p = p.then(() => exec.splice(exec.indexOf(_p), 1));
        //? 这段在p未执行完成时会直接执行 入数组 所以上面代码可以将其删除
        exec.push(_p);

        let next = Promise.resolve();
        //? 如果并发数超出限制
        if (exec.length >= limit) {
            //? next拿到最快执行结束的结果
            next = Promise.race(exec);
        }
        //? 递归 如果并发超过限制则是等待最快那个出来后递归 没有则直接执行
        return next.then(()=>_asyncPool());
    }
    //? 开启递归并等待其结果出来 然后通过Promise.all(会等待里面所有Promise状态都不为Pending时)返回所有异步操作的结果
    return _asyncPool().then(() => Promise.all(values));
}
